﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SisGAC.Filters;
using SisGAC.Models;
using WebMatrix.WebData;

namespace SisGAC.Controllers
{
    [InitializeSimpleMembership]
    public class ArtigosController : Controller
    {
        private SisgacContext db = new SisgacContext();

        //
        // GET: /Artigos/

        public ActionResult Index(int id)
        {
            int userid = WebSecurity.CurrentUserId;

            List<Artigo> artigos = new List<Artigo>();
            
            Congresso congresso = db.Congressos.Find(id);
            
            ViewBag.CongressoId = id;
            ViewBag.Title = string.Format("Artigos do Congresso {0}", congresso.Titulo);

            artigos = db.Artigos.Where(a => a.Congresso.CongressoId == id).ToList();
         
            //Se for coordenador do congresso, mostra todos os artigos do congressos
            if (userid == congresso.Coordenador.Account.UserId)
            {
                ViewBag.Coordenador = true;
                return View(artigos);
            }
            else
            {
                //Se a data final de avaliação já passou, mostra todos os artigos aprovados do congresso
                //Se não mostra os artigos cadastrados pelo usuário logado
                if (congresso.DataFimAvaliacao < DateTime.Today)
                    artigos = artigos.Where(a => a.Situacao == "Classificado").ToList();
                else
                    artigos = artigos.Where(a => a.CadastradoPor.UserId == userid).ToList();
            }

            return View(artigos);
        }

        //
        // GET: /Artigos/Details/5

        public ActionResult Details(int id = 0)
        {
            Artigo artigo = db.Artigos.Find(id);
            if (artigo == null)
            {
                return HttpNotFound();
            }
            return View(artigo);
        }

        public ActionResult Download(int id)
        {
            Artigo artigo = db.Artigos.Find(id);
            if (artigo.Arquivo != null)
                return File(artigo.Arquivo, artigo.TipoConteudoArquivo);
            else
                return HttpNotFound();
        }

        //
        //GET: /Artigos/Cadastro
        [Authorize]
        public ActionResult Cadastro(int id = 0, int idcongresso = 0)
        {
            Congresso congresso = new Congresso();
            if (idcongresso > 0)
            {
                congresso = db.Congressos.Find(idcongresso);

                if (congresso.DataFimSubmissao < DateTime.Today)
                {
                    return RedirectToAction("AcessoNegado", "Home", new
                    {
                        mensagem = string.Format("O período para emissão de artigos para o congresso {0} já terminou.", congresso.Titulo)
                    });
                }
                else if (congresso.DataInicioSubmissao > DateTime.Today)
                {
                    return RedirectToAction("AcessoNegado", "Home", new
                    {
                        mensagem = string.Format("O período para emissão de artigos para o congresso {0} ainda não iniciou.", congresso.Titulo)
                    });
                }
            }

            ArtigoViewModel model = new ArtigoViewModel();
            model.Artigo = new Artigo();
            //Listas de opções
            model.Autores = new SelectList(db.Pessoas.Where(p => p.Autor).ToList(), "PessoaId", "Nome");
            //model.Areas = db.Areas.ToList();
            model.Areas = new SelectList(db.Areas.ToList(), "AreaId", "Nome");

            //Se estiver editando um artigo pega informações do banco
            if (id > 0)
            {
                model.Artigo = db.Artigos.Find(id);
                if (model.Artigo == null)
                    return HttpNotFound();
                model.AutoresSelecionados = model.Artigo.Autores.Select(a => a.PessoaId).ToList();
                model.AreaId = model.Artigo.Area.AreaId;
            }
            else if (idcongresso > 0)
                model.Artigo.Congresso = congresso;
            else
                return RedirectToAction("AcessoNegado", "Home", new
                {
                    mensagem = "O artigo precisa ser criado em um congresso."
                });
           
            return View(model);
        }

        //
        // POST: /Artigos/Cadastro
        [Authorize]
        [HttpPost]
        public ActionResult Cadastro(FormCollection form, HttpPostedFileBase file)
        {
            int id = 0;
            if (!string.IsNullOrEmpty(form["Artigo.ArtigoId"]))
                id = Convert.ToInt32(form["Artigo.ArtigoId"]);

            Artigo artigo = new Artigo();
            
            //Se estiver editando um artigo, busca artigo do banco
            if (id > 0)
            {
                artigo = db.Artigos.Find(id);
                artigo.Autores.Clear();
            }
            else
            {
                artigo.DataCriacao = DateTime.Now;
                artigo.Situacao = "Incluído";
                artigo.CadastradoPor = db.UserProfiles.Find(WebSecurity.CurrentUserId);

                int idCongresso = Convert.ToInt32(form["Artigo.Congresso.CongressoId"]);
                Congresso congresso = db.Congressos.Find(idCongresso);
                artigo.Congresso = congresso;
            }

            //Atualiza dados do artigo
            artigo.Titulo = (string)form["Artigo.Titulo"];
            artigo.NumeroAutores = Convert.ToInt32(form["Artigo.NumeroAutores"]);
            artigo.Area = db.Areas.Find(Convert.ToInt32(form["AreaId"]));
            artigo.Observacao = (string)form["Artigo.Observacao"];
            artigo.Resumo = (string)form["Artigo.Resumo"];
            artigo.Abstract = (string)form["Artigo.Abstract"];

            //Atualiza lista de autores
            string[] autores = form["AutoresSelecionados"].Split(',');
            List<Pessoa> listAutores = new List<Pessoa>();
            foreach (var s in autores)
            {
                int idAutor = Convert.ToInt32(s);
                listAutores.Add(db.Pessoas.Find(idAutor));
            }
            artigo.Autores = listAutores;


            if (file != null)
            {
                int tamanho = file.ContentLength;
                byte[] tempFile = new byte[tamanho];
                file.InputStream.Read(tempFile, 0, tamanho);
                artigo.Arquivo = tempFile;
                artigo.TipoConteudoArquivo = file.ContentType;
            }            

            if (id == 0)
                db.Artigos.Add(artigo);

            //Salva alterações no banco
            db.SaveChanges();

            return RedirectToAction("Index", new { id = artigo.Congresso.CongressoId });
        }

        //
        // GET: /Artigos/Delete/5
        [Authorize(Roles="Coordenador")]
        public ActionResult Delete(int id = 0)
        {
            Artigo artigo = db.Artigos.Find(id);
            if (artigo == null)
            {
                return HttpNotFound();
            }
            return View(artigo);
        }

        //
        // POST: /Artigos/Delete/5

        [HttpPost, ActionName("Delete")]
        public ActionResult DeleteConfirmed(int id)
        {
            Artigo artigo = db.Artigos.Find(id);
            db.Artigos.Remove(artigo);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        [Authorize(Roles="Coordenador")]
        public ActionResult Distribuir(int idcongresso = 0)
        {
            DistribuirArtigosViewModel vm = new DistribuirArtigosViewModel();

            List<Congresso> congressos = new List<Congresso>();
            if (idcongresso == 0)
                congressos = db.Congressos.Where(c => c.Coordenador.Account.UserId == WebSecurity.CurrentUserId && c.DataFimSubmissao < DateTime.Today).ToList();
            else
            {
                Congresso congresso = db.Congressos.Find(idcongresso);
                if (congresso.DataFimSubmissao > DateTime.Today)
                    return RedirectToAction("AcessoNegado", "Home", new
                        {
                            mensagem = string.Format("O período para submissão de artigos para o congresso {0} ainda não terminou.", congresso.Titulo)
                        });
                else if (congresso.DataFimAvaliacao < DateTime.Today)
                    return RedirectToAction("AcessoNegado", "Home", new
                    {
                        mensagem = string.Format("O período para avaliação de artigos para o congresso {0} já terminou.", congresso.Titulo)
                    });
                else
                    congressos.Add(congresso);                        
            }

            //trazer apenas áreas que tenham artigos nos congressos
            List<Area> areas = new List<Area>();
            foreach (var congresso in congressos)
            {
                foreach (var artigo in congresso.Artigos)
                {
                    if (areas.Count(a => a.AreaId == artigo.Area.AreaId) == 0)
                        areas.Add(artigo.Area);
                }
            }

            vm.Congressos = new SelectList(congressos, "CongressoId", "Titulo");
            vm.Areas = new SelectList(areas, "AreaId", "Nome");

            return View(vm);
        }

        [HttpPost]
        [Authorize(Roles="Coordenador")]
        public ActionResult Distribuir(DistribuirArtigosViewModel distribuirVm)
        {
            Area area = db.Areas.Find(distribuirVm.AreaId);
            Congresso congresso = db.Congressos.Find(distribuirVm.CongressoId);

            distribuirVm.Artigos = congresso.Artigos.Where(a => a.Area.AreaId == area.AreaId && a.Avaliacoes.Count == 0).ToList();
            
            distribuirVm.NomeArea = area.Nome;
            distribuirVm.NomeCongresso = congresso.Titulo;

            return View(distribuirVm);
        }

        [Authorize(Roles="Coordenador")]
        public ActionResult ExecutarDistribuicao(int areaid, int congressoid)
        {
            Area area = db.Areas.Find(areaid);
            Congresso congresso = db.Congressos.Find(congressoid);

            var artigos = congresso.Artigos.Where(a => a.Area.AreaId == area.AreaId && a.Avaliacoes.Count == 0).ToList();
            var avaliadores = area.Avaliadores.Where(p => p.Avaliador);

            int indiceAvaliador = 0;
            int totalAvaliadores = avaliadores.Count();

            if (totalAvaliadores > 0)
            {
                foreach (Artigo artigo in artigos)
                {
                    //Verifica se o artigo já não foi ditribuído
                    if (artigo.Avaliacoes.Count > 0)
                        continue;

                    //Três avaliadores por artigo
                    for (int i = 0; i < 3; i++)
                    {
                        Pessoa avaliador = avaliadores.ElementAt(indiceAvaliador);

                        //Cria nova relação Avaliador-Artigo
                        AvaliacaoArtigo avaliacao = new AvaliacaoArtigo
                        {
                            Artigo = artigo,
                            Avaliador = avaliador
                        };

                        //Salva registro da avaliação
                        db.AvaliacoesArtigos.Add(avaliacao);

                        //Envia email para o avaliador
                        Utils.SendMail(avaliador.Email, 
                            "SISGAC - Novos artigos para avaliação", 
                            "Você possui um novo artigo pendente de avaliação no SISGAC. <br /> http://sisgac.apphb.com");

                        indiceAvaliador++;

                        //Caso a lista de avaliadores chegue ao fim, reinicia do primeiro
                        if (indiceAvaliador == totalAvaliadores)
                            indiceAvaliador = 0;
                    }

                    //Atualiza situação do artigo
                    artigo.Situacao = "Em Avaliação";
                    db.Entry(artigo).State = EntityState.Modified;

                }

                db.SaveChanges();

                ViewBag.Message = "Distribuição efetuada com sucesso";
            }
            else
            {
                ViewBag.Message = string.Format("Não existem avaliadores cadastrados para a área {0}", area.Nome);
            }

            return View(artigos.ToList());
           
        }

        [Authorize(Roles="Avaliador")]
        public ActionResult Avaliar()
        {
            int userid = WebSecurity.CurrentUserId;
            List<AvaliacaoArtigo> avaliacoes = db.AvaliacoesArtigos.Include("Artigo").Include("Artigo.Area").Where(av => av.Avaliador.Account.UserId == userid).ToList();
            return View(avaliacoes);
      
        }

        [Authorize(Roles="Avaliador")]
        public ActionResult AtribuirNotas(int id)
        {
            AvaliacaoArtigo avaliacao = db.AvaliacoesArtigos.Find(id);
            List<Criterio> criterios = db.Criterios.ToList();
            
            foreach (var c in criterios)
            {
                if (avaliacao.Notas.Count(n => n.Criterio.CriterioId == c.CriterioId) == 0)
                {
                    avaliacao.Notas.Add(new NotaAvaliacao { Criterio = c, Avaliacao = avaliacao });
                }
            }

            db.SaveChanges();

            return View(avaliacao.Notas);
        }

        [Authorize(Roles="Avaliador")]
        public JsonResult SalvarNotas(int id, double[] item_nota)
        {
            AvaliacaoArtigo avaliacao = db.AvaliacoesArtigos.Find(id);
            
            if (avaliacao.Notas.Count != item_nota.Length)
                return Json(false);

            int cont = 0;
            foreach (var nota in avaliacao.Notas)
            {
                nota.Nota = item_nota[cont];
                cont++;
            }

            db.SaveChanges();

            return Json(true);
        }

        [Authorize(Roles="Coordenador")]
        public ActionResult Classificar(int idcongresso)
        {
            //Lista os artigos do congresso, ordenados por nota, com um checkbox para marcar os classificados
            //Botão salvar no final. Número de classificados não pode ultrapassar máximo do congresso
            Congresso congresso = db.Congressos.Find(idcongresso);

            ViewBag.NumeroArtigos = congresso.NumeroArtigos;

            List<ArtigoAvaliadoViewModel> artigosAvaliados = new List<ArtigoAvaliadoViewModel>();

            if (congresso.DataFimAvaliacao < DateTime.Today)
            {
                var artigos = congresso.Artigos;
                int numCriterios = db.Criterios.Count();
                foreach (var item in artigos)
                {
                    //Se possui  notas altera situação
                    if (item.Situacao != "Classificado")
                    {
                        if (item.Avaliacoes.Count(av => av.Notas.Count > 0) > 0)
                            item.Situacao = "Avaliado";
                        else
                            item.Situacao = "Não avaliado";
                    }
                    artigosAvaliados.Add(new ArtigoAvaliadoViewModel { Artigo = item, Nota = item.Avaliacoes.Sum(a => a.Notas.Sum(n => n.Nota)) / numCriterios });
                }
                artigosAvaliados.OrderBy(a => a.Nota);
            }
            else
                ViewBag.Message = "O prazo para submissão e avaliação dos artigos ainda não terminou";

            return View(artigosAvaliados);
        }

        [HttpPost]
        [Authorize(Roles = "Coordenador")]
        public ActionResult Classificar(int[] classificados, int numArtigos)
        {
            if (classificados.Length == numArtigos)
            {
                foreach (var item in classificados)
                {
                    Artigo artigo = db.Artigos.Find(item);
                    artigo.Situacao = "Classificado";
                    db.SaveChanges();
                }                
                return Json(true, JsonRequestBehavior.AllowGet);
            }
            else
                return Json(false, JsonRequestBehavior.AllowGet);
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}